home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcl
/
src-16f.lha
/
ldb
/
egets.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-06
|
17KB
|
629 lines
/* $Header: egets.c,v 1.1 90/02/24 19:37:15 wlott Exp $ */
/********************************************************************
* *
* *
* Copyright (C) 1987, Carnegie Mellon University *
* *
* *
********************************************************************/
/* egets.c -- replacement for C library's gets(3s)
* allows emacs style command editing if stdin is a tty
* Derek Beatty
* HISTORY
* 20 Nov 87 Beatty: added code for more-mode.
* More-mode is handled by this file so gets can reset
* its line count.
*/
#include <stdio.h>
#include <ctype.h>
#include <sgtty.h>
#include <signal.h>
#include <strings.h>
#include <setjmp.h>
int getpid(); /* this should have been declared somewhere */
/*LINTLIBRARY*/
#define TRUE (1)
#define FALSE (0)
typedef unsigned char uchar;
#define HISTBUF (2000)
#define LINEBUF (132)
#define CONTROL(x) ((x)&0x1F)
#define META(x) ((x)|0x80)
#define BELL CONTROL('g')
#define ESC (0x1B)
#define RUBOUT (0x7F)
#define ISCONTROL(x) ((x)<0x20 || (x)>0x7E) /* includes meta */
#define NOTPREFIX(c) ((c)!=ESC)
/** Global Variables for user settings */
int ScrollPauseSwitch;
int ScreenLengthLimit;
int EditSwitch = TRUE;
/** Shared by MORE and GETS **/
static int CurrentLine = 1;
static int Initialized = FALSE;/* true iff initialize has been called */
/** VARIABLES FOR GETS **/
static struct sgttyb OttyFlags, NttyFlags;
static struct ltchars OltChars, NltChars;
#ifdef SIGTSTP
static int (*TstpHandler)();
#endif SIGTSTP
static int Active = TRUE; /* true iff egets is working */
static uchar History[HISTBUF]; /* history buffer */
static uchar
*FirstHistory, /* ptr to earliest line in history buffer */
*YankedHistory; /* ptr to history last yanked */
static uchar KillBuf[LINEBUF+1]; /* kill buffer */
static uchar Line[LINEBUF+1]; /* line being entered, plus null */
static uchar
*Cursor, /* ptr to character cursor is on */
*Bol, /* ptr to first char of line */
*Eol; /* ptr to null that terminates line */
static uchar tLine[LINEBUF+1]; /* line displayed on terminal */
static uchar *tCursor, *tBol, *tEol;
static uchar Meta = 0; /* meta bit; 0x80 if meta key was last */
static int Bleep = FALSE; /* TRUE iff bell needed at next screen update */
static jmp_buf out_of_here;
static void saveTtyModes(), restoreTtyModes(), initialize(), showLine(),
killToEol(), yankNext(), yankPrev(), yankKillBuf(),
transpose(), openSpace(), closeSpace();
/* saveTtyModes -- save tty state and put tty into cbreak mode */
static void
saveTtyModes()
{
(void) ioctl(fileno(stdin), TIOCGETP, (char*) &OttyFlags);
NttyFlags = OttyFlags;
NttyFlags.sg_flags |= CBREAK;
NttyFlags.sg_flags &= ~XTABS;
NttyFlags.sg_flags &= ~ECHO;
(void) ioctl(fileno(stdin), TIOCSETN, (char*) &NttyFlags);
(void) ioctl(fileno(stdin), TIOCGLTC, (char*) &OltChars);
NltChars = OltChars;
NltChars.t_dsuspc = NltChars.t_suspc;
(void) ioctl(fileno(stdin), TIOCSLTC, (char*) &NltChars);
}
/* restoreTtyModes -- restore tty state */
static void
restoreTtyModes()
{
(void) ioctl(fileno(stdin), TIOCSLTC, (char*) &OltChars);
(void) ioctl(fileno(stdin), TIOCSETN, (char*) &OttyFlags);
}
/* isaCRT -- return nonzero iff fd is a tty with CRT bits set */
static int
isaCRT( fd)
int fd;
{
int ltbits;
(void) ioctl(fd, TIOCLGET, (char*) <bits);
return (ltbits & (LCRTERA | LCRTKIL));
}
/* tstp -- handler for SIGTSTP: restore tty and suspend */
#ifdef SIGTSTP
int
tstp()
{
if (TstpHandler == SIG_IGN)
return;
restoreTtyModes();
if (TstpHandler == SIG_DFL)
(void) kill(getpid(), SIGSTOP);
else
(*TstpHandler) ();
saveTtyModes();
tBol = tEol = tCursor = tLine;
tLine[0] = '\0';
showLine();
}
#endif
/* initialize -- init data structures used by gets and more. called once. */
static void
initialize()
{
int i;
/* initialization for gets */
Initialized = TRUE;
YankedHistory = FirstHistory = History;
for (i = 0; i < HISTBUF; i++)
History[i] = '\0';
KillBuf[0] = '\0';
/* initialization for more */
ScrollPauseSwitch= isaCRT(fileno(stdin)) && isatty(fileno(stdout));
ScreenLengthLimit= -1;
#ifdef TIOCGWINSZ /* 4.3bsd window size */
{
struct winsize wss;
ioctl(fileno(stdin), TIOCGWINSZ, (char*) &wss);
ScreenLengthLimit= wss.ws_row-1;
}
#endif
#ifdef TIOCGSIZE /* sun window size */
{
struct ttysize tss;
ioctl(fileno(stdin), TIOCGSIZE, (char*) &tss);
ScreenLengthLimit= tss.ts_lines-1;
}
#endif
if (ScreenLengthLimit==-1)
ScreenLengthLimit = 24;
}
/* killToEol -- delete characters on and following cursor into kill buffer */
static void
killToEol()
{
int n = strlen( (char*) Cursor);
(void) strcpy((char*) KillBuf, (char*) Cursor);
closeSpace(n);
}
/* transpose -- transpose two characters preceding cursor */
static void
transpose()
{
if (Cursor <= Bol + 1)
Bleep = TRUE;
else {
uchar c = *(Cursor - 1);
*(Cursor - 1) = *(Cursor - 2);
*(Cursor - 2) = c;
}
}
/* numInWord -- return number of chars through word before or after cursor */
static int
numInWord( before)
int before; /* true iff want count in word before cursor */
{
uchar *tempCursor = Cursor;
int n;
if (before) {
if (tempCursor > Bol)
tempCursor--;
else
Bleep = TRUE;
while (tempCursor > Bol && !isalnum(*tempCursor))
tempCursor--;
while (tempCursor > Bol && isalnum(*tempCursor))
tempCursor--;
n = Cursor - tempCursor;
if (n != 0 && !isalnum(*tempCursor))
n--;
return (n);
} else {
if (tempCursor >= Eol)
Bleep = TRUE;
while (tempCursor < Eol && !isalnum(*tempCursor))
tempCursor++;
while (tempCursor < Eol && isalnum(*tempCursor))
tempCursor++;
return (tempCursor - Cursor);
}
}
/* yankHistory -- yank line at YankedHistory into Line */
static void
yankHistory()
{
uchar *tempHistory;
YankedHistory++;
if (YankedHistory >= History + HISTBUF)
YankedHistory = History;
tempHistory = YankedHistory;
Bol = Cursor = Line;
while (*tempHistory) {
*Cursor++ = *tempHistory++;
if (tempHistory >= History + HISTBUF)
tempHistory = History;
}
*Cursor = '\0';
Eol = Cursor;
}
/* yankNext -- yank the next line from the history buffer */
static void
yankNext()
{
while (*YankedHistory) {
YankedHistory++;
if (YankedHistory >= History + HISTBUF)
YankedHistory = History;
}
yankHistory();
}
/* yankPrev -- yank the previous line from the history buffer */
static void
yankPrev()
{
YankedHistory--;
if (YankedHistory < History)
YankedHistory = History + HISTBUF - 1;
YankedHistory--;
if (YankedHistory < History)
YankedHistory = History + HISTBUF - 1;
while (*YankedHistory) {
YankedHistory--;
if (YankedHistory < History)
YankedHistory = History + HISTBUF - 1;
}
yankHistory();
}
/* addHistory -- add the current line to the history buffer */
static void
addHistory()
{
uchar *tempCursor = Bol;
while (*tempCursor) {
*FirstHistory++ = *tempCursor++;
if (FirstHistory >= History + HISTBUF)
FirstHistory = History;
}
*FirstHistory++ = '\0';
if (FirstHistory >= History + HISTBUF)
FirstHistory = History;
YankedHistory = FirstHistory;
}
/* yankKillBuf -- insert kill buffer in current line. Bleep if trouble */
static void
yankKillBuf()
{
uchar *sourceCursor = KillBuf;
uchar *destCursor = Cursor;
int n = strlen((char*) KillBuf);
if (Eol + n > Line + LINEBUF)
Bleep = TRUE;
else {
openSpace(n);
while (*sourceCursor)
*destCursor++ = *sourceCursor++;
Cursor += n;
}
}
/* redraw -- force showLine to redraw current line on screen */
static void
redraw()
{
tCursor = tBol = tEol = tLine;
tLine[0] = '\0';
printf("\n");
(void) fflush(stdout);
}
/* showLine -- update screen and tLine to reflect Line */
static void
showLine()
{
uchar *Dif, *tDif;
/* find first place the lines differ */
Dif = Bol;
tDif = tBol;
while (*Dif && *tDif && *Dif == *tDif) {
Dif++;
tDif++;
}
if (*Dif || *tDif) {
/* lines differ: move tCursor to the point of difference */
while (tCursor > tDif) {
printf("\b");
tCursor--;
}
while (tCursor < tDif)
printf("%c", *tCursor++);
/* write remainder of Line */
while (*Dif)
printf("%c", *tCursor++ = *Dif++);
/* add blanks to bring tLine up to length of Line */
while (tCursor < tEol) {
printf(" ");
*tCursor++ = '\0';
}
/* adjust tEol */
tEol = tBol + (Eol - Bol);
}
/* move tCursor to proper place */
while (tCursor - tBol > Cursor - Bol) {
printf("\b");
tCursor--;
}
while (tCursor - tBol < Cursor - Bol)
printf("%c", *tCursor++);
/* cleanup */
if (Bleep) {
printf("%c", BELL);
Bleep = FALSE;
}
(void) fflush(stdout);
}
/* openSpace -- open space for n characters at cursor. Beep if trouble. */
static void
openSpace( n)
int n;
{
uchar *sourceCursor, *destCursor;
if (n == 0)
return;
destCursor = Eol + n;
if (destCursor > Line + LINEBUF + 1)
Bleep = TRUE;
else {
sourceCursor = Eol;
Eol = destCursor;
while (sourceCursor >= Cursor)
*destCursor-- = *sourceCursor--;
}
}
/* closeSpace -- close space for n characters at cursor. Bleep if trouble. */
static void
closeSpace( n)
int n;
{
uchar *sourceCursor, *destCursor;
if (n == 0)
return;
if (n > Eol - Cursor) {
Bleep = TRUE;
n = Eol - Cursor;
}
sourceCursor = Cursor + n;
destCursor = Cursor;
while (sourceCursor <= Eol)
*destCursor++ = *sourceCursor++;
Eol = destCursor - 1;
}
/* ogets -- get a line without command line editing */
static char *
ogets(s, n)
char *s;
int n; /* total length of string */
{
int c, i;
char *t;
t = s; i = n;
if (n <= 0)
return NULL;
while ((--i > 0) && ((c = getchar()) != '\n') && (c != EOF))
*t++ = c;
if ((n != 1) && (c == EOF) && (s == t))
return NULL;
*t = '\0';
return(s);
}
static sigint_handler()
{
longjmp(out_of_here, 1);
}
/* egets -- get a line from stdin with command line editing */
char *
egets()
{
uchar c= '\0';
int done, returnEOF;
long int buffered= 0L;
int n;
int arg = 0;
int gettingArg = FALSE, gettingDigitArg = FALSE;
int stillGettingArg = FALSE;
struct sigvec sv, old_int_sv;
if (!EditSwitch
|| !Active
|| (!Initialized && (!isatty(fileno(stdin)) ))
|| !isaCRT(fileno(stdin))) {
Active = FALSE;
return (ogets(Line, LINEBUF + 1));
}
if (!Initialized)
initialize();
fflush(stdout);
CurrentLine=1; /* Reset line count for more-mode. */
Line[0] = '\0';
tLine[0] = '\0';
Cursor = Bol = Eol = Line;
tCursor = tBol = tEol = tLine;
#ifdef SIGTSTP
TstpHandler = signal(SIGTSTP, tstp);
#endif
saveTtyModes();
if (setjmp(out_of_here))
returnEOF = TRUE;
else {
sv.sv_handler = sigint_handler;
sv.sv_mask = 0;
sv.sv_flags = 0;
sigvec(SIGINT, &sv, &old_int_sv);
returnEOF = done = FALSE;
while (!done) {
/* lint complains that c may be used before set */
if (!gettingArg && arg > 0 && NOTPREFIX(c))
arg--;
else {
if (read(fileno(stdin), (char*) &c, 1) == 0)
c = CONTROL('m');
else {
c |= Meta;
Meta = 0;
}
}
if (ISCONTROL(c)) {
switch (c) {
case CONTROL('a'):
Cursor = Bol;
break;
case CONTROL('b'):
if (Cursor > Bol)
Cursor--;
else
Bleep = TRUE;
break;
case CONTROL('d'):
if (Cursor < Eol)
closeSpace(1);
else
Bleep = TRUE;
break;
case CONTROL('e'):
Cursor = Eol;
break;
case CONTROL('f'):
if (Cursor < Eol)
Cursor++;
else
Bleep = TRUE;
break;
case CONTROL('h'):
case RUBOUT:
if (Cursor > Bol) {
Cursor--;
closeSpace(1);
} else
Bleep = TRUE;
break;
case CONTROL('j'):
done = TRUE;
break;
case CONTROL('k'):
killToEol();
break;
case CONTROL('m'):
done = TRUE;
break;
case CONTROL('n'):
yankNext();
break;
case CONTROL('p'):
yankPrev();
break;
case CONTROL('r'):
redraw();
break;
case CONTROL('t'):
transpose();
break;
case CONTROL('u'):
if (gettingArg)
arg *= 4;
else
arg = 4;
stillGettingArg = TRUE;
gettingDigitArg = FALSE;
break;
case CONTROL('y'):
yankKillBuf();
break;
case ESC:
Meta = 0x80;
break;
case META('f'):
Cursor += numInWord(0);
break;
case META('b'):
Cursor -= numInWord(1);
break;
case META('d'):
closeSpace(numInWord(0));
break;
case CONTROL('w'):
case META('h'):
n = numInWord(1);
Cursor -= n;
closeSpace(n);
break;
case META(CONTROL('d')):
if (Bol == Eol)
done = returnEOF = TRUE;
else
Bleep = TRUE;
break;
default:
Bleep = TRUE;
break;
}
} else if (!gettingArg || !isdigit(c)) {
if (Eol + 1 > Line + LINEBUF)
Bleep = TRUE;
else {
openSpace(1);
*Cursor++ = c;
}
} else {
/* getting argument digits */
if (gettingDigitArg)
arg = 10 * arg + c - '0';
else
arg = c - '0';
stillGettingArg = TRUE;
gettingDigitArg = TRUE;
}
if (gettingArg && !stillGettingArg)
arg--;
gettingArg = stillGettingArg;
stillGettingArg = FALSE;
if (Bleep)
arg = 0;
(void) ioctl(fileno(stdin), FIONREAD, (char*) &buffered);
if ((buffered == 0L && arg == 0) || done)
showLine();
}
addHistory();
}
if (!returnEOF) printf("\n");
(void) fflush(stdout);
restoreTtyModes();
#ifdef SIGTSTP
(void) signal(SIGTSTP, TstpHandler);
#endif
sigvec(SIGINT, &old_int_sv, NULL);
return (returnEOF ? NULL : (char *) Line);
}